import axios, {type AxiosInstance, AxiosRequestConfig, CancelTokenSource, InternalAxiosRequestConfig} from "axios"
import {ElLoading, ElMessage} from "element-plus"
import {get, merge} from "lodash-es"
import {AjaxResult} from "@/entityType/AjaxResult";
import {LoadingUtils} from "@/utils/LoadingUtils";

/** 退出登录并强制刷新页面（会重定向到登录页） */
export function logout() {
  location.reload()
}

export interface MyConfig {
  isSearchList?: boolean; // 是否是列表搜索
  exportFile?: boolean; // 是否是导出文件
  showLoading?: boolean; // 是否显示loading，默认显示
}

export interface MyInternalAxiosRequestConfig<D> extends InternalAxiosRequestConfig<D>, MyConfig {

}

export interface MyAxiosRequestConfig<D extends unknown> extends AxiosRequestConfig<D>, MyConfig {
}

/** 创建请求实例 */
function createService() {
  // 创建一个 axios 实例命名为 service
  const service = axios.create()
  // 请求拦截
  service.interceptors.request.use(
    (config: MyInternalAxiosRequestConfig<any>) => {
      //自定义文件请求
      if (config.exportFile === true) {
        config.responseType = 'blob'
        config.timeout = undefined
      }
      if (config.isSearchList === true) {
        let data = config.data || {}
        if (config.params) {
          config.params.pageNum = data.pageNum
          config.params.pageSize = data.pageSize
        } else {
          config.params = {
            pageNum: data.pageNum,
            pageSize: data.pageSize
          }
        }
      }
      return config
    },
    // 发送失败
    (error) => Promise.reject(error)
  )
  // 响应拦截（可根据具体业务作出相应的调整）
  service.interceptors.response.use(
    (response) => {
      // apiData 是 api 返回的数据
      const apiData = response.data
      // 二进制数据则直接返回
      const responseType = response.request?.responseType
      if (responseType === "blob" || responseType === "arraybuffer") return response
      // 这个 code 是和后端约定的业务 code
      const code = apiData.code
      // 如果没有 code, 代表这不是项目后端开发的 api
      if (code === undefined) {
        ElMessage.error("非本系统的接口")
        return Promise.reject(new Error("非本系统的接口"))
      }
      switch (code) {
        case 200:
          return apiData
        case 401:
          // Token 过期时
          return logout()
        default:
          // 不是正确的 code
          ElMessage.error(apiData.message || "Error")
          return Promise.reject(new Error("Error"))
      }
    },
    (error) => {
      // status 是 HTTP 状态码
      const status = get(error, "response.status")
      switch (status) {
        case 400:
          error.message = "请求错误"
          break
        case 401:
          // Token 过期时
          logout()
          break
        case 403:
          error.message = "拒绝访问"
          break
        case 404:
          error.message = "请求地址出错"
          break
        case 408:
          error.message = "请求超时"
          break
        case 500:
          error.message = "服务器内部错误"
          break
        case 501:
          error.message = "服务未实现"
          break
        case 502:
          error.message = "网关错误"
          break
        case 503:
          error.message = "服务不可用"
          break
        case 504:
          error.message = "网关超时"
          break
        case 505:
          error.message = "HTTP 版本不受支持"
          break
        default:
          break
      }
      ElMessage.error(error.message)
      return Promise.reject(error)
    }
  )
  return service
}

/** 创建请求方法 */
function createRequest(service: AxiosInstance) {
  return function <T>(config: MyAxiosRequestConfig<T>): Promise<AjaxResult<T>> {
    const defaultConfig = {
      headers: {
        // "Content-Type": "application/json"
      },
      timeout: 1000 * 60,
      baseURL: import.meta.env.VITE_BASE_API,
      data: {}
    }
    // 将默认配置 defaultConfig 和传入的自定义配置 config 进行合并成为 mergeConfig
    const mergeConfig = merge(defaultConfig, config)
    return service(mergeConfig)
  }
}

let loadingInstance
let loadingUtils = new LoadingUtils((loading) => {
  setTimeout(() => {
    if (loading) {
      loadingInstance = ElLoading.service({fullscreen: true, text: "加载中，请稍候", background: "rgba(0,0,0,0.18)",})
    } else {
      if (loadingInstance) {
        loadingInstance.close()
      }
    }
  })
})

/** 用于网络请求的实例 */
const service = createService()

let oldReq = createRequest(service)

/** 用于网络请求的方法 */
export function request<D>(args: MyAxiosRequestConfig<any>): Promise<AjaxResult<D>> {
  if (args.showLoading !== false) {
    return loadingUtils.autoLoading(oldReq(args))
  } else {
    return oldReq(args)
  }
}

export function getCancelToken(): CancelTokenSource {
  return axios.CancelToken.source()
}
